use anyhow::anyhow;
use std::ops::{Add, AddAssign, Deref, Index, Mul, MulAssign};

pub struct Vector<T> {
    data: Vec<T>,
}

impl<T> Deref for Vector<T> {
    type Target = Vec<T>;
    fn deref(&self) -> &Self::Target {
        &self.data
    }
}

//pretend this is heavy operator
pub fn dot_product<T>(a: Vector<T>, b: Vector<T>) -> anyhow::Result<T>
where
    T: Copy + Default + Add<T, Output = T> + AddAssign<T> + Mul<T, Output = T> + MulAssign<T>,
{
    if a.len() != b.len() {
        //a.len()=>a.data.len() (Deref trait)
        return Err(anyhow!(
            "Matrix len not equal to length of arrays".to_string()
        ));
    }

    let mut sum = T::default();

    for i in 0..a.len() {
        sum += a[i] * b[i];
    }
    Ok(sum)
}

impl<T> Vector<T> {
    pub fn new(data: impl Into<Vec<T>>) -> Vector<T> {
        Vector { data: data.into() }
    }

    // pub fn len(&self) -> usize {
    //     self.data.len()
    // }
    //
    // pub fn iter(&self) -> Iter<T> {
    //     self.data.iter()
    // }
}

impl<T> Index<usize> for Vector<T> {
    type Output = T;

    fn index(&self, index: usize) -> &Self::Output {
        &self.data[index]
    }
}
